package web.servlet;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

import web.clazz.Clazz;
import web.jdbc.DataOperator;
import web.jdbc.FieldsGetSet;
import web.operator.ClassOperator;
import web.operator.EntityOperator;
import web.operator.TypeOperator;
import web.util.CharSet;
import web.util.Constant;
import web.util.Log;
import web.util.InvolkeResult;

/**拦截、处理请求，并返回处理结果
 * 
 * @author 乐渊
 * @version 1.0
 * @see TypeOperator
 * @see EntityOperator
 * @see DataOperator
 * @see Clazz
 * @see FieldsGetSet
 * @see CharSet
 * @see Log
 * */
public class WebServlet extends HttpServlet {

	/**
	 */
	private static final long serialVersionUID = 1L;

	private Log log = new Log();

	private HttpServletRequest request;
	private HttpServletResponse response;
	
	private boolean isReturnPage;

	public HttpServletRequest getRequest() {
		return request;
	}

	public void setRequest(HttpServletRequest request) {
		this.request = request;
	}

	public HttpServletResponse getResponse() {
		return response;
	}

	public void setResponse(HttpServletResponse response) {
		this.response = response;
	}

	@Override
	public void init() throws ServletException {
		super.init();
		/** 获取要扫描的包 */
		String packageName = getInitParameter("packages");
		String[] packageNames = packageName.split(",");
		/** 初始化 */
		new ClassOperator().getClazzCollection(packageNames);
		new TypeOperator();
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/** 保存请求 */
		setRequest(request);
		setResponse(response);
		
		String uri = request.getRequestURI();
		uri = uri.substring(uri.lastIndexOf("/") + 1, uri.length());
		String[] requestPath = uri.split("\\.");
		
		String type = request.getContentType();
		//是否为上传文件请求
		if(type != null && type.contains("multipart/form-data")){
			getFile(requestPath);
		}else{
			/** 调用方法获取返回值 */
			Object returnObject = runMethod(request, response,requestPath,uri);
			if(!isReturnPage || returnObject instanceof InvolkeResult){
				response.setCharacterEncoding("UTF-8");
				response.getWriter().print(returnObject);
				response.getWriter().flush();
			}else{
				/** 如果包含JSP 则跳转到目标JSP 否则将返回值返回到请求页面 */
				try {
					if(returnObject instanceof InvolkeResult) {
						InvolkeResult rr = (InvolkeResult) returnObject;
						if(rr.getPage() != null && !rr.getPage().trim().equals("")) {
							request.getRequestDispatcher(rr.getPage()).forward(request, response);
						}
						
					}else {
						/** 继续执行请求 */
						request.getRequestDispatcher(returnObject + "").forward(request, response);
					}
				} catch (ServletException | IOException e) {
					log.setLog(Constant._503+"{"+returnObject+"}");
					e.printStackTrace();
				}
			}
		}
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doGet(req, resp);
	}

	/**
	 * 调用方法 获取方法的返回值
	 * @param request
	 * @param response
	 * @return returnObject 返回结果
	 */
	private Object runMethod(HttpServletRequest request, HttpServletResponse response,String[] requestPath,String uri) {
		/** 请求链接分为三段 : 类的别名.方法别名.过滤规则 （如：userController.showUser.do） */
		
		Object returnObject = null;
		if (requestPath.length > 2) {
			boolean isMethodRun = true;
			/**获取目标Controller*/
			Clazz clazz = null;
			try{
				clazz = TypeOperator.Types.stream().filter(claz -> requestPath[0].equals(claz.getName())).findFirst().get();
			}catch(NoSuchElementException e){
				log.setLog(Constant._501+"{不存在的Controller别名："+requestPath[0]+"}");
				return null;
			}
			if (clazz != null) {
				/** 获取参数名*/
				List<String> paramNames = clazz.getParams().get(requestPath[1]);
				/** 声明参数值空间，参数值要保存为Object数组、以便调用方法时使用 */
				Object[] paramValues = new Object[paramNames.size()];
				/** 获取目标方法各参数的类型，用于判断是否有实体类型的参数 */
				Class<?>[] paramTypes = clazz.getMethod().get(requestPath[1]).getParameterTypes();
				isReturnPage = clazz.getmReturnType().get(requestPath[1]).booleanValue(); 
				try {
					/** 为各参数填充值，flag保证一次只填充一个参数的值 */
					for (int i = 0; i < paramNames.size(); i++) {
						Class<?>[] paramType = {paramTypes[i]};
						/**获取目标Entity（如果参数有实体类型）*/
						Clazz c = null;
						try{
							c = EntityOperator.Entities.stream().filter(cla -> cla.getClazz() == paramType[0]).findFirst().get();
						}catch(NoSuchElementException e){
							//参数类型不是Entity类型
						}
						
						if (c != null) {
							/** 填充实体类型参数的值 */
							Map<Field, Method> FM = FieldsGetSet.getFieldGetOrSet(paramTypes[i], "set");
							
							/*String key = c.getKey().keySet().iterator().next(); 2017/2/15*/
							Object o = paramTypes[i].newInstance();
							for (Field field : FM.keySet()) {
								String paramValue = request.getParameter(paramNames.get(i) + "." + field.getName());
								paramValue = CharSet.parseStringToUTF(paramValue);
								/**参数赋值给实体对象时需要转型*/
								/*if(!field.getName().equals(key) && c.isKeyAuto()) 2017/2/15*/
								FM.get(field).invoke(o,new Object[] { DataOperator.parseData(field.getType(), paramValue) });
							}
							paramValues[i] = o;
						}else {
							String paramValue = request.getParameter(paramNames.get(i));
							paramValue = CharSet.parseStringToUTF(paramValue);
							paramValues[i] = paramValue;
						}
					}

					System.out.println("执行:"+clazz.getMethod().get(requestPath[1]));
					/** 获取类的实例 用于执行该类的方法 */
					Object object = clazz.getClazz().newInstance();
					/** 执行方法并接收返回结果 */
					returnObject = clazz.getMethod().get(requestPath[1]).invoke(object, paramValues);
					
					Map<String, Object> map = new HashMap<>();
					/** 为request绑定数据，用于JSP获取数据，通过调用Controller类中成员的get方法获取值存入map，再将map存入request */
					clazz.getMembers().forEach((key,value) ->{
						try {
							map.put(key, value.invoke(object));
						} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
							log.setLog(Constant._502+"{"+key+"}");
							e.printStackTrace();
						}
					});
					request.setAttribute(clazz.getName(), map);

					isMethodRun = false;
				} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
						| InstantiationException e) {
					log.setLog(Constant._500+"{"+uri+"}");
					e.printStackTrace();
				}
			}
			if (isMethodRun)
				log.setLog(Constant._404+"{"+uri+"}");
		} else {
			log.setLog(Constant._501+"{"+uri+"}");
		}
		return returnObject;
	}
	
	
	public void getFile(String[] requestPath){
		Part part = null;
		Clazz clazz;
		try{
			clazz = EntityOperator.Entities.stream().filter(claz -> requestPath[0].equals(claz.getName())).findFirst().get();
		}catch(NoSuchElementException e){
			log.setLog(Constant._501+"{不存在的Controller别名："+requestPath[0]+"}");
			return;
		}
		if (clazz != null) {
			/**获取文件name值*/
			String paramName = clazz.getParams().get(requestPath[1]).get(0);
			try {
				part = request.getPart(paramName);
				if(part == null){
					log.setLog("# 请检查File控件的name值是不是{"+paramName+"}");
					return;
				}
				
				try {
					clazz.getMethod().get(requestPath[1]).invoke(clazz.getClazz().newInstance(), new Object[]{part});
				} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
						| InstantiationException e) {
					e.printStackTrace();
				}
				
			} catch (IOException | ServletException e) {
				e.printStackTrace();
				log.setLog(Constant._404);
			}
		}
	}
}
